'use strict';

import { app, protocol, BrowserWindow, dialog, ipcMain } from 'electron';
const { parallel } = require('async');
const officegen = require('officegen');
const mammoth = require('mammoth');
import fs from 'fs';
import path from 'path';
import os from 'os';
import { createProtocol } from 'vue-cli-plugin-electron-builder/lib';
import installExtension, { VUEJS3_DEVTOOLS } from 'electron-devtools-installer';
const isDevelopment = process.env.NODE_ENV !== 'production';

// Scheme must be registered before the app is ready
protocol.registerSchemesAsPrivileged([{ scheme: 'app', privileges: { secure: true, standard: true } }]);
let win: BrowserWindow;
let isDocPreview: boolean = false;
let fileName: string = 'example';
async function createWindow() {
  // Create the browser window.
  win = new BrowserWindow({
    width: 950,
    // frame: false,
    // transparent: true,
    height: 600,
    webPreferences: {
      // Use pluginOptions.nodeIntegration, leave this alone
      // See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info
      nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION as unknown as boolean,
      contextIsolation: !process.env.ELECTRON_NODE_INTEGRATION
    }
  });

  if (process.env.WEBPACK_DEV_SERVER_URL) {
    // Load the url of the dev server if in development mode
    await win.loadURL(process.env.WEBPACK_DEV_SERVER_URL as string);
    if (!process.env.IS_TEST) win.webContents.openDevTools();
  } else {
    createProtocol('app');
    // Load the index.html when not in development
    win.loadURL('app://./index.html');
  }


}

// Quit when all windows are closed.
app.on('window-all-closed', () => {
  // On macOS it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

app.on('activate', () => {
  // On macOS it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  if (BrowserWindow.getAllWindows().length === 0) createWindow();
});

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', async () => {
  if (isDevelopment && !process.env.IS_TEST) {
    // Install Vue Devtools
    try {
      console.log(VUEJS3_DEVTOOLS);
      await installExtension(VUEJS3_DEVTOOLS);
    } catch (e) {
      console.error('Vue Devtools failed to install:', e.toString());
    }
  }
  createWindow();
});

// Exit cleanly on request from parent process in development mode.
if (isDevelopment) {
  if (process.platform === 'win32') {
    process.on('message', (data) => {
      if (data === 'graceful-exit') {
        app.quit();
      }
    });
  } else {
    process.on('SIGTERM', () => {
      app.quit();
    });
  }
}

/// 生成docx文档
const outTempDir = path.join(__dirname, '../_tmp/');
if (!fs.existsSync(outTempDir)) {
  fs.mkdirSync(outTempDir);
}

/// 打开文件夹获取路径
ipcMain.on('open-file-dialog', async function (event) {
  let dir = await dialog.showOpenDialog(win, {
    properties: ['openDirectory']
  })
  /// 把选中的文件夹路径传过去
  if (!dir.canceled && dir.filePaths.length) {
    event.sender.send('selected-directory', dir.filePaths[0]);
  }
});

/// 生成doc文件
ipcMain.on('create-doc-file', async function (event, data) {

  console.log('----> create-doc-file')

  /// 多少道题
  const COUNT = data.math_count
  const IS_SOLUTION = data.is_solution
  const TYPE: keyof ITITLE_TIPS = data.math_type
  const OVER_COUNT: number = data.math_over_count
  const COUNT_LINE = data.math_count_line
  const CACHE_MATHS: any = {}
  const ISPREVIEW: boolean = data.isPreview || false
  const FILE_NAME: string = data.file_name || 'example'
  let pObj = null;
  let docx: any = null;
  isDocPreview = data.isPreview
  fileName = FILE_NAME
  interface ITITLE_TIPS {
    add: string
    sub: string
    add_sub: string
  }

  const TITLE_TIPS: ITITLE_TIPS = {
    'add': '加法',
    'sub': '减法',
    'add_sub': '加减法',
  }

  /// utils
  const createSpace = (po: any, space: number) => po.addText(' '.repeat(space));
  const createUnderline = (po: any, space: number) => po.addText('_'.repeat(space));
  const fixZero = (n: number): string => {
    return n.toString().padStart(OVER_COUNT.toString().length, '  ')
  }

  /// 加法规则
  const createAddTopic = (po: any, topic: string, index: number) => {
    po.addText(`${topic}`)
    createSpace(po, 6);
    if ((index + 1) % COUNT_LINE === 0) {
      po.addText('\n')
      po.addText('\n')
    }
  };

  /// 生成随机数
  function randomNum(minNum: number, maxNum: number) {
    switch (arguments.length) {
      case 1:
        let vN = Math.random() * minNum + 1
        return parseInt(vN.toString(), 10);
      case 2:
        const v = Math.random() * (maxNum - minNum + 1) + minNum
        return parseInt(v.toString(), 10);
      default:
        return 0;
    }
  }

  /// 生成对象
  function _createMathTopic(count: number) {

    /// 如果数量已经相等直接renturn
    if (Object.keys(CACHE_MATHS).length === COUNT) return

    /// 循环生成题目
    for (let index = 0; index < count; index++) {
      const a = randomNum(0, OVER_COUNT);
      const other_number_area = OVER_COUNT - a;
      const b = randomNum(0, other_number_area);
      const vStr = `${fixZero(a)}  +  ${fixZero(b)}  =  (  ${IS_SOLUTION ? fixZero(a + b) : ''}  )`
      CACHE_MATHS[vStr] = true
    }

    /// 判断是否有重复
    if (Object.keys(CACHE_MATHS).length < COUNT) {
      _createMathTopic(COUNT - Object.keys(CACHE_MATHS).length);
    }
  }

  /// 生成加法函数
  const createAddStr = (pObj: any) => {
    _createMathTopic(COUNT);

    Object.keys(CACHE_MATHS).forEach((topic, index) => {
      createAddTopic(pObj, topic, index);
    })
  }

  docx = officegen('docx')
  /// 生成doc文件成功
  docx.on('finalize', (written: any) => {
    event.sender.send('cb-create-doc-finished', { temp_folder_path: outTempDir, isPreview: isDocPreview })
  });

  /// 生成doc文件失败
  docx.on('error', function (err: any) {
    event.sender.send('cb-create-doc-error')
  });
  const titleStyle = {
    font_face: os.platform() === 'darwin' ? 'Calibri' : 'Arial',
    font_size: 18,
    color: '#000000',
    bold: true,
  }

  /// 标题
  pObj = docx.createP({ align: 'center' });
  pObj.addText(`${OVER_COUNT}以内整数${TITLE_TIPS[TYPE]}`, titleStyle);

  /// 姓名 | 年月日 | 分数
  pObj = docx.createP({ align: 'center' })
  pObj.addText('姓名')
  createUnderline(pObj, 8)
  createSpace(pObj, 12)
  createUnderline(pObj, 4)
  pObj.addText('年')
  createUnderline(pObj, 4)
  pObj.addText('月')
  createUnderline(pObj, 4)
  pObj.addText('日')
  createSpace(pObj, 12)
  pObj.addText('分数')
  createUnderline(pObj, 4)

  /// 生成题
  pObj = docx.createP()
  pObj.addText('\n')
  pObj.addText('\n')

  /// 根据类型生成不同规则的题目
  switch (TYPE) {
    case 'add':
      createAddStr(pObj);
      break;

    default:
      break;
  }
  pObj.addText('\n')
  pObj.addText('\n')


  /// 如果不是预览模式直接把缓存文件删掉
  /// 防止体积越来越大
  if (!ISPREVIEW) {
    const _fp = path.join(outTempDir, `${FILE_NAME}_tmp.docx`);
    if (fs.existsSync(_fp)) {
      fs.unlinkSync(_fp)
    }
  }
  const filenameSuffix = ISPREVIEW ? '_tmp.docx' : '.docx';
  const filePath = path.join(ISPREVIEW ? outTempDir : data.save_path, `${FILE_NAME}${filenameSuffix}`);
  if (fs.existsSync(filePath)) {
    fs.unlinkSync(filePath)
  }
  var out = fs.createWriteStream(filePath)

  out.on('error', function (err) {
    console.log(err)
  })

  parallel(
    [
      function (done: any) {
        out.on('close', function () {
          console.log('Finish to create a DOCX file.')
          done(null)
        })
        docx.generate(out)
      }
    ],
    function (err: any) {
      if (err) {
        console.log('error: ' + err)
      } // Endif.
    }
  )

});

/// 生成完之后如果是预览模式，需要读取docx文件然后生成html
ipcMain.on('preview-doc', async (event, data) => {
  console.log('preview-doc', outTempDir + `${fileName}_tmp.docx`);
  setTimeout(() => {
    mammoth.convertToHtml({
      path: outTempDir + `${fileName}_tmp.docx`
    }).then(function (result: any) {
      event.sender.send('cb-preview-doc-html-success', { html: result.value })
    })
  }, 3000)
});